import express from 'express';
import { prisma } from '../app';
import { asyncHandler, createError } from '../middleware/errorHandler';
import { authenticateToken, AuthRequest } from '../middleware/auth';

const router = express.Router();

// Get user activities for heatmap (contribution graph)
router.get('/heatmap', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const userId = req.user!.id;
  const { year } = req.query;

  const targetYear = year ? parseInt(year as string) : new Date().getFullYear();
  
  if (isNaN(targetYear) || targetYear < 2020 || targetYear > 2030) {
    throw createError('Invalid year parameter', 400);
  }

  const startDate = new Date(targetYear, 0, 1); // January 1st
  const endDate = new Date(targetYear + 1, 0, 1); // January 1st of next year

  const activities = await prisma.userActivity.findMany({
    where: {
      userId,
      date: {
        gte: startDate,
        lt: endDate
      }
    },
    orderBy: {
      date: 'asc'
    }
  });

  // Transform data for heatmap
  const heatmapData = activities.map(activity => ({
    date: activity.date.toISOString().split('T')[0], // YYYY-MM-DD format
    count: activity.count
  }));

  // Calculate statistics
  const totalActivities = activities.reduce((sum, activity) => sum + activity.count, 0);
  const activeDays = activities.length;
  const maxDayCount = activities.length > 0 ? Math.max(...activities.map(a => a.count)) : 0;
  
  // Calculate streak (consecutive days with activities)
  let currentStreak = 0;
  let maxStreak = 0;
  let tempStreak = 0;
  
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  
  // Sort activities by date descending to calculate current streak
  const sortedActivities = [...activities].sort((a, b) => b.date.getTime() - a.date.getTime());
  
  for (let i = 0; i < sortedActivities.length; i++) {
    const activityDate = new Date(sortedActivities[i].date);
    const expectedDate = new Date(today);
    expectedDate.setDate(today.getDate() - i);
    
    if (activityDate.getTime() === expectedDate.getTime()) {
      currentStreak++;
    } else {
      break;
    }
  }
  
  // Calculate max streak
  for (let i = 0; i < activities.length; i++) {
    if (i === 0) {
      tempStreak = 1;
    } else {
      const prevDate = new Date(activities[i - 1].date);
      const currDate = new Date(activities[i].date);
      const dayDiff = (currDate.getTime() - prevDate.getTime()) / (1000 * 60 * 60 * 24);
      
      if (dayDiff === 1) {
        tempStreak++;
      } else {
        maxStreak = Math.max(maxStreak, tempStreak);
        tempStreak = 1;
      }
    }
  }
  maxStreak = Math.max(maxStreak, tempStreak);

  res.json({
    success: true,
    data: {
      year: targetYear,
      activities: heatmapData,
      statistics: {
        totalActivities,
        activeDays,
        maxDayCount,
        currentStreak,
        maxStreak
      }
    }
  });
}));

// Get recent activities
router.get('/recent', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const userId = req.user!.id;
  const { limit = 10 } = req.query;

  const limitNum = parseInt(limit as string);
  if (isNaN(limitNum) || limitNum < 1 || limitNum > 100) {
    throw createError('Limit must be between 1 and 100', 400);
  }

  const activities = await prisma.userActivity.findMany({
    where: { userId },
    orderBy: { date: 'desc' },
    take: limitNum
  });

  res.json({
    success: true,
    data: { activities }
  });
}));

// Get activity statistics
router.get('/stats', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const userId = req.user!.id;
  const { period = '30' } = req.query;

  const days = parseInt(period as string);
  if (isNaN(days) || days < 1 || days > 365) {
    throw createError('Period must be between 1 and 365 days', 400);
  }

  const startDate = new Date();
  startDate.setDate(startDate.getDate() - days);
  startDate.setHours(0, 0, 0, 0);

  const activities = await prisma.userActivity.findMany({
    where: {
      userId,
      date: {
        gte: startDate
      }
    },
    orderBy: { date: 'asc' }
  });

  const totalActivities = activities.reduce((sum, activity) => sum + activity.count, 0);
  const activeDays = activities.length;
  const averagePerDay = activeDays > 0 ? totalActivities / activeDays : 0;
  
  // Get total counts for different entities
  const [totalProblems, totalTodos, totalCompletedTodos] = await Promise.all([
    prisma.algorithmProblem.count({ where: { userId } }),
    prisma.todo.count({ 
      where: { 
        list: { userId } 
      } 
    }),
    prisma.todo.count({ 
      where: { 
        list: { userId },
        completed: true
      } 
    })
  ]);

  res.json({
    success: true,
    data: {
      period: days,
      totalActivities,
      activeDays,
      averagePerDay: Math.round(averagePerDay * 100) / 100,
      totalProblems,
      totalTodos,
      totalCompletedTodos,
      completionRate: totalTodos > 0 ? Math.round((totalCompletedTodos / totalTodos) * 100) : 0
    }
  });
}));

// Manually record an activity (for testing or manual tracking)
router.post('/record', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const userId = req.user!.id;
  const { date, count = 1 } = req.body;

  let targetDate: Date;
  
  if (date) {
    targetDate = new Date(date);
    if (isNaN(targetDate.getTime())) {
      throw createError('Invalid date format', 400);
    }
  } else {
    targetDate = new Date();
  }
  
  targetDate.setHours(0, 0, 0, 0);

  if (typeof count !== 'number' || count < 1 || count > 100) {
    throw createError('Count must be between 1 and 100', 400);
  }

  const activity = await prisma.userActivity.upsert({
    where: {
      userId_date: {
        userId,
        date: targetDate
      }
    },
    update: {
      count: {
        increment: count
      }
    },
    create: {
      userId,
      date: targetDate,
      count
    }
  });

  res.json({
    success: true,
    message: 'Activity recorded successfully',
    data: { activity }
  });
}));

export default router;